package org.example.order.controller;

import com.github.pagehelper.PageInfo;
import jakarta.annotation.Resource;
import org.example.order.common.APIResponse;
import org.example.order.common.GoodFilter;
import org.example.order.common.ResponseCode;
import org.example.order.entity.Good;
import org.example.order.exception.GoodNotFoundException;
import org.example.order.exception.IllegalGoodFilterException;
import org.example.order.exception.IllegalRequestParamException;
import org.example.order.permission.Access;
import org.example.order.permission.AccessLevel;
import org.example.order.service.GoodService;
import org.example.order.service.RecommendService;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/good")
public class GoodController {
    @Resource
    private GoodService service;
    @Resource
    private RecommendService recommendService;

    /// 用户级别获取商品列表，status过滤将不生效
    @GetMapping("/list")
    public APIResponse<PageInfo<Good>> list(@ModelAttribute GoodFilter filter) {
        // 强制只能获取已上架的商品
        filter.setStatus("1");
        return getGoodList(filter);
    }

    /// 管理员级别获取商品列表
    @Access(level = AccessLevel.ADMIN)
    @GetMapping("/goods")
    public APIResponse<PageInfo<Good>> goods(@ModelAttribute GoodFilter filter) {
        return getGoodList(filter);
    }

    @Access(level = AccessLevel.ADMIN)
    @PostMapping("/add")
    public APIResponse<List<Good>> add(@RequestBody Good good) {
        try {
            service.addGood(good);
        } catch (GoodNotFoundException e) {
            return new APIResponse<>(ResponseCode.NOT_FOUND, e.getMessage());
        } catch (Exception e) {
            return new APIResponse<>(ResponseCode.INTERNAL_SERVER_ERROR, e.getMessage());
        }
        return new APIResponse<>(ResponseCode.SUCCESS);
    }

    @Access(level = AccessLevel.ADMIN)
    @PutMapping("/update")
    public APIResponse<Void> update(@RequestBody Good good) {
        try {
            service.updateGood(good);
        } catch (GoodNotFoundException e) {
            return new APIResponse<>(ResponseCode.NOT_FOUND, e.getMessage());
        }  catch (Exception e) {
            return new APIResponse<>(ResponseCode.INTERNAL_SERVER_ERROR, e.getMessage());
        }
        return new APIResponse<>(ResponseCode.SUCCESS);
    }

    @Access(level = AccessLevel.ADMIN)
    @DeleteMapping("/deleteById")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public APIResponse<Void> delete(@RequestBody Good good) {
        try {
            service.deleteGood(good.getId());
        } catch (GoodNotFoundException e) {
            return new APIResponse<>(ResponseCode.NOT_FOUND, e.getMessage());
        } catch (Exception e) {
            return new APIResponse<>(ResponseCode.INTERNAL_SERVER_ERROR, e.getMessage());
        }
        return new APIResponse<>(ResponseCode.SUCCESS);
    }

    @GetMapping("/getGoodById")
    public APIResponse<Good> getGoodById(@RequestParam Long id) {
        try {
            Good good = service.getGood(id);
            return new APIResponse<>(ResponseCode.SUCCESS, good);
        } catch (GoodNotFoundException e) {
            return new APIResponse<>(ResponseCode.NOT_FOUND, e.getMessage());
        } catch (Exception e) {
            return new APIResponse<>(ResponseCode.INTERNAL_SERVER_ERROR, e.getMessage());
        }
    }

    /// 浏览量 + 1
    @PutMapping("/view")
    public APIResponse<Void> view(@RequestBody Good good) {
        try {
            if (good.getId() == null) {
                throw new IllegalRequestParamException("参数id不存在");
            }
            Good currentGood = getCurrentGood(good.getId());
            currentGood.setViewCount(currentGood.getViewCount() + 1);
            service.updateGood(currentGood);
            return new APIResponse<>(ResponseCode.SUCCESS);
        } catch (GoodNotFoundException e) {
            return new APIResponse<>(ResponseCode.NOT_FOUND, e.getMessage());
        } catch (Exception e) {
            return new APIResponse<>(ResponseCode.INTERNAL_SERVER_ERROR, e.getMessage());
        }
    }

    public record GoodOperation(Long id, String operation) {}

    /// 收藏/取消点赞
    /// 接受参数: { "id": 1, "operation": "like"(default) } or { "id": 1, "operation": "cancel" }
    @PutMapping("/like")
    public APIResponse<Void> like(@RequestBody GoodOperation operation) {
        if (operation.id == null) {
            return new APIResponse<>(ResponseCode.FAIL, "参数错误");
        }
        try {
            Good currentGood = getCurrentGood(operation.id);
            switch (operation.operation) {
            case "like":
                currentGood.setLikeCount(currentGood.getLikeCount() + 1);
                break;
            case "cancel":
                if (currentGood.getLikeCount() > 0) {
                    currentGood.setLikeCount(currentGood.getLikeCount() - 1);
                }
                break;
            default:
                throw new IllegalRequestParamException(operation.operation);
            }
            service.updateGood(currentGood);
            return new APIResponse<>(ResponseCode.SUCCESS);
        } catch (IllegalRequestParamException e) {
            return new APIResponse<>(ResponseCode.FAIL, e.getMessage());
        } catch (GoodNotFoundException e) {
            return new APIResponse<>(ResponseCode.NOT_FOUND, e.getMessage());
        } catch (Exception e) {
            return new APIResponse<>(ResponseCode.INTERNAL_SERVER_ERROR, e.getMessage());
        }
    }

    /// 收藏/取消收藏
    /// 接受参数: { "id": 1, "operation": "collect"(default) } or { "id": 1, "operation": "cancel" }
    @PutMapping("/collect")
    public APIResponse<Void> collect(@RequestBody GoodOperation operation) {
        if (operation.id == null) {
            return new APIResponse<>(ResponseCode.FAIL, "参数错误");
        }
        try {
            Good currentGood = getCurrentGood(operation.id);
            switch (operation.operation) {
                case "collect":
                    currentGood.setCollectCount(currentGood.getCollectCount() + 1);
                    break;
                case "cancel":
                    if (currentGood.getCollectCount() > 0) {
                        currentGood.setCollectCount(currentGood.getCollectCount() - 1);
                    }
                    break;
                default:
                    throw new IllegalRequestParamException(operation.operation);
            }
            service.updateGood(currentGood);
            return new APIResponse<>(ResponseCode.SUCCESS);
        } catch (IllegalRequestParamException e) {
            return new APIResponse<>(ResponseCode.FAIL, e.getMessage());
        } catch (GoodNotFoundException e) {
            return new APIResponse<>(ResponseCode.NOT_FOUND, e.getMessage());
        } catch (Exception e) {
            return new APIResponse<>(ResponseCode.INTERNAL_SERVER_ERROR, e.getMessage());
        }
    }

    @GetMapping("/recommend")
    public APIResponse<List<Long>> recommend(
            @RequestParam Long userId,
            @RequestParam(defaultValue = "5") Integer topK
    ) {
        try {
            var userItem = recommendService.getUserItem();
            var itemUserCount = recommendService.getItemUserCount(userItem);
            var coOccurrence = recommendService.getCoOccurrence(userItem);
            var goodSimilarities = recommendService.getGoodSimilarities(itemUserCount, coOccurrence);
            var result = recommendService.getRecommendations(userId, topK, goodSimilarities);
            return new APIResponse<>(ResponseCode.SUCCESS, result);
        } catch (Exception e) {
            return new APIResponse<>(ResponseCode.INTERNAL_SERVER_ERROR, e.getMessage());
        }
    }

    private APIResponse<PageInfo<Good>> getGoodList(@ModelAttribute GoodFilter filter) {
        PageInfo<Good> goods;
        try {
            goods = service.getGoodsByFilter(filter);
        } catch (IllegalGoodFilterException e) {
            return new APIResponse<>(ResponseCode.FAIL, e.getMessage());
        } catch (Exception e) {
            return new APIResponse<>(ResponseCode.INTERNAL_SERVER_ERROR, e.getMessage());
        }
        return new APIResponse<>(ResponseCode.SUCCESS, goods);
    }

    private Good getCurrentGood(Long id) {
        Good good = service.getGood(id);
        if (good == null) {
            throw new GoodNotFoundException("商品不存在");
        }
        return good;
    }

}
